﻿# coding: utf-8

import os
import wx
import wx.lib.agw.floatspin as FS

import TerrainLayerBrush

BRUSH_SIZE = 64

class wxPanelTerrainLayer(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        
        # Layout
        sizerBrushList = self.__CreateUIBrushList()
        sizerLayerList = self.__CreateUILayerList()
        sizerBrushParam = self.__CreateUIBrushParam()
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(sizerBrushList, 1, wx.ALL|wx.EXPAND, border = 10)
        sizer.Add(sizerLayerList, 1, wx.ALL|wx.EXPAND, border = 10)
        sizer.Add(sizerBrushParam, 0, wx.ALL|wx.EXPAND, border = 10)
        self.SetSizer(sizer)
        
        # Bind brush list event.
        self.Bind(wx.EVT_CONTEXT_MENU, self.__OnContextMenu)
        self._idMenuAddBrush = wx.NewId()
        self._idMenuRemoveBrush = wx.NewId()
        self._idMenuAddLayer = wx.NewId()
        self._idMenuRemoveLayer = wx.NewId()
        self.Bind(wx.EVT_MENU, self.__OnMenuAddBrush, id = self._idMenuAddBrush)
        self.Bind(wx.EVT_MENU, self.__OnMenuRemoveBrush, id = self._idMenuRemoveBrush)
        self.Bind(wx.EVT_MENU, self.__OnMenuAddLayer, id = self._idMenuAddLayer)
        self.Bind(wx.EVT_MENU, self.__OnMenuRemoveLayer, id = self._idMenuRemoveLayer)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__OnBrushSelected, self._listBrush)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__OnLayerSelected, self._listLayer)
        
        # Bind brush parameter event.
        self._fsBrushSize.Bind(FS.EVT_FLOATSPIN, self.__OnFloatSpinBrushSize)
        self._fsBrushPowerFactor.Bind(FS.EVT_FLOATSPIN, self.__OnFloatSpinBrushPowerFactor)
        
    def LoadLayerBrush(self):
        """ Load all layer brushes and layers that last used. """
        
        for path in GLOBAL_SETTING._terrainLayerBrushList:
            if not path or not TERRAIN_EDITOR.AddTerrainLayerBrush(path):
                continue
                
            fullPath = GLOBAL_SETTING._workDir + path
            bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
            if bmp:
                self.__AddBrush(bmp, path)
                
        for path in GLOBAL_SETTING._terrainLayerList:                
            fullPath = GLOBAL_SETTING._workDir + path
            bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
            if bmp:
                self.__AddLayer(bmp, path)
            
    def __OnFloatSpinBrushSize(self, e):
        """ Set brush size """
        
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        size = self._fsBrushSize.GetValue()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentLayerBrushHandle()
        if brushCoreHandle:
            TerrainLayerBrush.SetSize(brushCoreHandle, size)
        
    def __OnFloatSpinBrushPowerFactor(self, e):
        """ Set brush power factor """
        
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        powerFactor = self._fsBrushPowerFactor.GetValue()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentLayerBrushHandle()
        if brushCoreHandle:
            TerrainLayerBrush.SetPowerFactor(brushCoreHandle, powerFactor)        
        
    def __CreateUIBrushList(self):
        """ Create brush list """

        self._ilBrush = wx.ImageList(BRUSH_SIZE, BRUSH_SIZE)
        self._listBrush = wx.ListCtrl(self, wx.NewId(), style = wx.LC_ICON|wx.LC_SINGLE_SEL|wx.LC_AUTOARRANGE)
        self._listBrush.SetImageList(self._ilBrush, wx.IMAGE_LIST_NORMAL)        
        sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, TD.TERRAIN_LAYER_BRUSH_LIST), wx.VERTICAL)        
        sizer.Add(self._listBrush, 1, wx.ALL|wx.EXPAND, border = 5)
        return sizer
        
    def __CreateUILayerList(self):
        """ Create layer list """
        
        self._ilLayer = wx.ImageList(BRUSH_SIZE, BRUSH_SIZE)
        self._listLayer = wx.ListCtrl(self, wx.NewId(), style = wx.LC_ICON|wx.LC_SINGLE_SEL|wx.LC_AUTOARRANGE)
        self._listLayer.SetImageList(self._ilLayer, wx.IMAGE_LIST_NORMAL)
        sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, TD.TERRAIN_LAYER_LIST), wx.VERTICAL)
        sizer.Add(self._listLayer, 1, wx.ALL|wx.EXPAND, border = 5)
        return sizer
        
    def __CreateUIBrushParam(self):
        """ Create brush parameter UI """
        
        # Height brush size
        staticBrushSize = wx.StaticText(self, -1, TD.TERRAIN_LAYER_BRUSH_SIZE)
        self._fsBrushSize = FS.FloatSpin(self, -1, min_val = 10.0, max_val = 1200.0, increment = 10.0, agwStyle = FS.FS_RIGHT)
        self._fsBrushSize.SetDigits(2)
        self._fsBrushSize.SetFormat('%f')
        sizerBrushSize = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushSize.Add(staticBrushSize, 0, wx.CENTER, border = 5)
        sizerBrushSize.Add(self._fsBrushSize, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        # Height power factor.
        staticBrushPowerFactor = wx.StaticText(self, -1, TD.TERRAIN_LAYER_BRUSH_POWER_FACTOR)
        self._fsBrushPowerFactor = FS.FloatSpin(self, -1, min_val = 0, max_val = 10.0, increment = 0.1, agwStyle = FS.FS_RIGHT)
        self._fsBrushPowerFactor.SetDigits(2)
        self._fsBrushPowerFactor.SetFormat('%f')
        sizerBrushPowerFactor = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushPowerFactor.Add(staticBrushPowerFactor, 0, wx.CENTER, border = 5)
        sizerBrushPowerFactor.Add(self._fsBrushPowerFactor, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        sizerBrushParam = wx.StaticBoxSizer(wx.StaticBox(self, -1, TD.TERRAIN_LAYER_BRUSH_PARAM), wx.VERTICAL)
        sizerBrushParam.Add(sizerBrushSize, 0, wx.ALL|wx.EXPAND, border = 5)
        sizerBrushParam.Add(sizerBrushPowerFactor, 0, wx.ALL|wx.EXPAND, border = 5)
        return sizerBrushParam
                
    def __AddBrush(self, bmp, name):
        """ Add a brush to the brush list control """
        
        idx = self._ilBrush.Add(bmp)
        assert(self._listBrush.GetItemCount() == idx)
        self._listBrush.InsertImageStringItem(self._listBrush.GetItemCount(), name, idx)
        
    def __AddLayer(self, bmp, name):
        """ Add a terrain layer to layer list control """
        
        idx = self._ilLayer.Add(bmp)
        assert(self._listLayer.GetItemCount() == idx)
        self._listLayer.InsertImageStringItem(self._listLayer.GetItemCount(), name, idx)
                
    def __OnContextMenu(self, e):
        menu = wx.Menu()
        menu.Append(self._idMenuAddBrush, TD.MENU_ADD_TERRAIN_LAYER_BRUSH)
        menu.Append(self._idMenuRemoveBrush, TD.MENU_REMOVE_TERRAIN_LAYER_BRUSH)
        menu.AppendSeparator()
        menu.Append(self._idMenuAddLayer, TD.MENU_ADD_TERRAIN_LAYER)
        menu.Append(self._idMenuRemoveLayer, TD.MENU_REMOVE_TERRAIN_LAYER)
        self.PopupMenu(menu)
        menu.Destroy()
        
    def __OnMenuAddBrush(self, e):
        dlg = wx.FileDialog(self, defaultDir = GLOBAL_SETTING._workDir, wildcard = u'All files (*.*)|*.*', style = wx.OPEN)
        path = ''
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()            

        dlg.Destroy()
        
        if not path:
            return

        path = REMOVE_ROOT_PATH(path)
            
        if not TERRAIN_EDITOR.AddTerrainLayerBrush(path):
            dlgMsg = wx.MessageDialog(self, TD.ERR_ADD_TERRAIN_LAYER_BRUSH_FAILED, TD.ERROR, wx.OK|wx.ICON_INFORMATION)
            dlgMsg.ShowModal()
            dlgMsg.Destroy()            
            return
            
        fullPath = GLOBAL_SETTING._workDir + path
        bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
        if bmp:
            self.__AddBrush(bmp, path)
            GLOBAL_SETTING._terrainLayerBrushList.append(path)
                    
    def __OnMenuAddLayer(self, e):
        dlg = wx.FileDialog(self, defaultDir = GLOBAL_SETTING._workDir, wildcard = u'All files (*.*)|*.*', style = wx.OPEN)
        path = ''
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()            

        dlg.Destroy()
        
        if not path:
            return

        path = REMOVE_ROOT_PATH(path)            
        fullPath = GLOBAL_SETTING._workDir + path
        bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
        if bmp:
            self.__AddLayer(bmp, path)
            GLOBAL_SETTING._terrainLayerList.append(path)
                                
    def __OnMenuRemoveBrush(self, e):
        idx = self._listBrush.GetNextItem(-1, state = wx.LIST_STATE_SELECTED)
        name = self._listBrush.GetItemText(idx)
        self._listBrush.DeleteItem(idx)
        for i in xrange(idx, self._listBrush.GetItemCount()):
            self._listBrush.SetItemImage(i, i)
            
        self._ilBrush.Remove(idx)
        TERRAIN_EDITOR.RemoveTerrainLayerBrush(name)
        GLOBAL_SETTING._terrainLayerBrushList.remove(name)
        
    def __OnMenuRemoveLayer(self, e):
        idx = self._listLayer.GetNextItem(-1, state = wx.LIST_STATE_SELECTED)
        name = self._listLayer.GetItemText(idx)
        self._listLayer.DeleteItem(idx)
        for i in xrange(idx, self._listLayer.GetItemCount()):
            self._listLayer.SetItemImage(i, i)
            
        self._ilLayer.Remove(idx)
        GLOBAL_SETTING._terrainLayerList.remove(name)
        
    def __OnBrushSelected(self, e):
        idx = e.m_itemIndex
        name = self._listBrush.GetItemText(idx)
        TERRAIN_EDITOR.UseLayerBrush(name)
        self.RefrehBrushParam()
        
    def __OnLayerSelected(self, e):
        idx = e.m_itemIndex
        name = self._listLayer.GetItemText(idx)
        TERRAIN_EDITOR.UseLayer(name)
        
    def RefrehBrushParam(self):
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentLayerBrushHandle()
        if not brushCoreHandle:
            return

        size = TerrainLayerBrush.GetSize(brushCoreHandle)
        powerFactor = TerrainLayerBrush.GetPowerFactor(brushCoreHandle)
        self._fsBrushSize.SetValue(float(size))
        self._fsBrushPowerFactor.SetValue(float(powerFactor))
